home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / djgpp / libsrc / pc / src / gppconio.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-01  |  18.8 KB  |  745 lines

  1. /**********************************************************************
  2.  *  
  3.  *  NAME:           gppconio.c
  4.  *  
  5.  *  DESCRIPTION:    simulate Borland text video funcs for GNU C++
  6.  *  
  7.  *  copyright (c) 1991 J. Alan Eldridge
  8.  * 
  9.  *  M O D I F I C A T I O N   H I S T O R Y
  10.  *
  11.  *  when        who                 what
  12.  *  -------------------------------------------------------------------
  13.  *  10/27/91    J. Alan Eldridge    created
  14.  *  01/06/92    D. Buerssner        make it work with extended characters
  15.  * (buers@dg1.chemie.uni-konstanz.de) speed-up of cputs
  16.  *                                  some missing brackets in VIDADDR
  17.  *                                  don't need scrollwindow anymore
  18.  *  07/15/93    D. Buerssner        take care of cursor tracking
  19.  *                                    txinfo.curx and txinfo.cury
  20.  *                                  fill in missing functionality
  21.  *                                    - textmode
  22.  *                                    - cscanf
  23.  *                                    - cgets
  24.  *                                    - getch and ungetch
  25.  *                                    - _setcursortype
  26.  *                                    - kbhit 
  27.  *                                  (hpefully) proper initialization of
  28.  *                                    txinfo.normattrib and txinfo.attribute  
  29.  *                                  gotoxy(1,1) in clrscr (bug introduced
  30.  *                                    by my previous patches)
  31.  *                                  gotoxy(1,1) in window
  32.  *                                  take care of BELL and BACKSPACE
  33.  *                                    in putch and cputs
  34.  *                                  take care of blinking bit in textcolor
  35.  *                                    and textbackground
  36.  *                                  declare (and ignore) directvideo 
  37.  *  10/09/93    DJ Delorie          Switch to dosmem*() for DPMI
  38.  *  05/01/94    DJ Delorie          Add _wscroll
  39.  *********************************************************************/
  40.  
  41. #include    <stdlib.h>
  42. #include    <stdio.h>
  43. #include    <stdarg.h>
  44. #include    <dos.h>
  45. #include    <pc.h>
  46. #include    <go32.h>
  47. #include    "gppconio.h"
  48.  
  49. int _wscroll = 1;
  50.  
  51. int directvideo = 1;  /* We ignore this */
  52.  
  53. static void setcursor(unsigned int shape);
  54. static int getvideomode(void);
  55. static void bell(void);
  56. static int get_screenattrib(void);
  57. static int isEGA(void);
  58. static int _scan_getche(FILE *fp);
  59. static int _scan_ungetch(int c, FILE *fp);
  60.  
  61. #define DBGGTINFO   0
  62.  
  63. static unsigned ScreenAddress = 0xb8000UL; /* initialize just in case */
  64. static struct text_info txinfo;
  65. static int ungot_char;
  66. static int char_avail = 0;
  67.  
  68. #define VIDADDR(r,c) (ScreenAddress + 2*(((r) * txinfo.screenwidth) + (c)))
  69.  
  70. int puttext(int c, int r, int c2, int r2, void *buf)
  71. {
  72.   short *cbuf = (short *)buf;
  73.   /* we should check for valid parameters, and maybe return 0 */
  74.   r--, r2--, c--, c2--;
  75.   for (; r <= r2; r++)
  76.   {
  77.     dosmemput(cbuf, (c2-c+1)*2, VIDADDR(r, c));
  78.     cbuf += c2-c+1;
  79.   }
  80.   return 1;
  81. }
  82.  
  83. int gettext(int c, int r, int c2, int r2, void *buf)
  84. {
  85.   short *cbuf = (short *)buf;
  86.   /* we should check for valid parameters, and maybe return 0 */
  87.   r--, r2--, c--, c2--;
  88.   for (; r <= r2; r++)
  89.   {
  90.     dosmemget(VIDADDR(r, c), (c2-c+1)*2, cbuf);
  91.     cbuf += c2-c+1;
  92.   }
  93.   return 1;
  94. }
  95.         
  96. void gotoxy(int col, int row)
  97. {
  98.   ScreenSetCursor(row + txinfo.wintop - 2, col + txinfo.winleft - 2);
  99.   txinfo.curx = col;
  100.   txinfo.cury = row;
  101. }
  102.  
  103. int wherex(void)
  104. {
  105.   int row, col;
  106.   
  107.   ScreenGetCursor(&row, &col);
  108.   
  109.   return col - txinfo.winleft + 2;
  110. }
  111.     
  112. int wherey(void)
  113. {
  114.   int row, col;
  115.   
  116.   ScreenGetCursor(&row, &col);
  117.   
  118.   return row - txinfo.wintop + 2;
  119. }
  120.  
  121. void textmode(int mode)
  122. {
  123.     union REGS regs;
  124.     int mode_to_set = mode;
  125.     if (mode == LASTMODE)
  126.         mode = mode_to_set = txinfo.currmode;
  127.     if (mode == C4350)
  128.         /* 
  129.          * just set mode 3 and load 8x8 font, idea taken 
  130.          * (and code translated from Assembler to C)
  131.          * form Csaba Biegels stdvga.asm
  132.          */
  133.         mode_to_set = 0x03;  
  134.     regs.h.ah = 0x00; /* set mode */
  135.     regs.h.al = mode_to_set;
  136.     int86(0x10, ®s, ®s);
  137.     if (mode == C80 || mode == BW80 || mode == C4350)
  138.     {
  139.         if (isEGA())
  140.         {
  141.             /* 
  142.              * enable cursor size emulation, see Ralf Browns
  143.              * interrupt list
  144.              */
  145.             regs.h.ah = 0x12;
  146.             regs.h.bl = 0x34;
  147.             regs.h.al = 0x00; /* 0: enable (1: disable) */
  148.             int86(0x10, ®s, ®s);
  149.     }
  150.     }
  151.     if (mode == C4350)
  152.     {
  153.         if (!isEGA())
  154.             return;
  155.         /* load 8x8 font */
  156.         regs.x.ax = 0x1112;         
  157.         regs.x.bx = 0;
  158.         int86(0x10, ®s, ®s);
  159.     }
  160. /*    _setcursortype(_NORMALCURSOR); */
  161.     /* reinitialize txinfo structure to take into account new mode */
  162.     gppconio_init();
  163. #if 0
  164.     /*
  165.      * For mode C4350 the screen is not cleared on my OAK-VGA.
  166.      * Should we clear it here? TURBOC doesn't so we don't bother either.
  167.      */
  168.     clrscr();
  169. #endif
  170. }    
  171.     
  172. void textattr(int attr)
  173. {
  174.   txinfo.attribute = ScreenAttrib = (unsigned char)attr;
  175. }
  176.  
  177. void textcolor(int color)
  178. {
  179.   /* strip blinking (highest) bit and textcolor */
  180.   ScreenAttrib &= 0x70; /* strip blinking (highest) bit and textcolor */
  181.   txinfo.attribute=(ScreenAttrib |= (color & 0x8f));
  182. }
  183.  
  184. void textbackground(int color)
  185. {
  186.   /* strip background color, keep blinking bit */
  187.   ScreenAttrib &= 0x8f; 
  188.   /* high intensity background colors (>7) are not allowed 
  189.      so we strip 0x08 bit (and higher bits) of color */
  190.   txinfo.attribute=(ScreenAttrib |= ((color & 0x07) << 4));
  191. }
  192.  
  193. void highvideo(void)
  194. {
  195.   txinfo.attribute=(ScreenAttrib |= 0x08);
  196. }
  197.  
  198. void lowvideo(void)
  199. {
  200.   txinfo.attribute=(ScreenAttrib &= 0x07);
  201. }
  202.  
  203. void normvideo(void)
  204. {
  205.   txinfo.attribute = ScreenAttrib = txinfo.normattr;
  206. }
  207.  
  208. void _setcursortype(int type)
  209. {
  210.     unsigned cursor_shape;
  211.     switch (type)
  212.     {
  213.         case _NOCURSOR:
  214.             cursor_shape = 0x0700;
  215.             break;
  216.         case _SOLIDCURSOR:
  217.             cursor_shape = 0x0007;
  218.             break;
  219. /*      case _NORMALCURSOR: */
  220.         default:
  221.             cursor_shape = 0x0607;
  222.             break;
  223.     }
  224.     setcursor(cursor_shape);
  225. }        
  226.  
  227. static void setcursor(unsigned int cursor_shape)
  228. /* Sets the shape of the cursor */
  229. {
  230.     union REGS      reg;
  231.  
  232.     reg.h.ah = 1;
  233.     reg.x.cx = cursor_shape;
  234.     int86(0x10, ®, ®);
  235. }                /* setcursor */
  236.  
  237. static void getwincursor(int *row, int *col)
  238. {
  239.   ScreenGetCursor(row, col);
  240. }
  241.  
  242. void clreol(void)
  243. {
  244.   short   image[ 256 ];
  245.   short   val = ' ' | (ScreenAttrib << 8);
  246.   int     c, row, col, ncols;
  247.   
  248.   getwincursor(&row, &col);
  249.   ncols = txinfo.winright - col;
  250.   
  251.   for (c = 0; c < ncols; c++)
  252.     image[ c ] = val;
  253.   
  254.   puttext(col + 1, row + 1, txinfo.winright, row + 1, image);
  255. }
  256.  
  257. static void fillrow(int row, int left, int right, int fill)
  258. {
  259.   int col;
  260.   short filler[right-left+1];
  261.   
  262.   for (col = left; col <= right; col++)
  263.     filler[col-left] = fill;
  264.   dosmemput(filler, (right-left+1)*2, VIDADDR(row, left));
  265. }
  266.  
  267. void clrscr(void)
  268. {
  269.   short filler[txinfo.winright - txinfo.winleft + 1];
  270.   int row, col;
  271.   for (col=0; col < txinfo.winright - txinfo.winleft + 1; col++)
  272.     filler[col] = ' ' | (ScreenAttrib << 8);
  273.   for (row=txinfo.wintop-1; row < txinfo.winbottom; row++)
  274.     dosmemput(filler, (txinfo.winright - txinfo.winleft + 1)*2,
  275.      VIDADDR(row, txinfo.winleft - 1));
  276.   gotoxy(1, 1);
  277. }
  278.  
  279. int putch(int c)
  280. {
  281.   int     row, col;
  282.   
  283.   ScreenGetCursor(&row, &col);
  284.   
  285.   /*  first, handle the character */
  286.   if (c == '\n')
  287.     {
  288.       row++;
  289.     }
  290.   else if (c == '\r')
  291.     {
  292.       col = txinfo.winleft - 1;
  293.     }
  294.   else if (c == '\b')
  295.   {
  296.       if (col > txinfo.winleft - 1)
  297.           col--;  
  298.       else if (row > txinfo.wintop -1)
  299.       {
  300.           /* 
  301.            * Turbo-C ignores this case; we are smarter.
  302.            */
  303.           row--;
  304.           col = txinfo.winright-1;
  305.       }  
  306.   }      
  307.   else if (c == 0x07)
  308.     bell();
  309.   else {
  310.     short   val = c | (ScreenAttrib << 8);
  311.     /* puttext(col + 1, row + 1, col + 1, row + 1, &val); */
  312.     ScreenPutChar(c, ScreenAttrib, col, row);
  313.     col++;
  314.   }
  315.   
  316.   /* now, readjust the window     */
  317.   
  318.   if (col >= txinfo.winright) {
  319.     col = txinfo.winleft - 1;
  320.     row++;
  321.   }
  322.   
  323.   if (row >= txinfo.winbottom) {
  324.     /* scrollwin(0, txinfo.winbottom - txinfo.wintop, 1); */
  325.     if (_wscroll)
  326.     {
  327.       ScreenSetCursor(txinfo.wintop-1,0);
  328.       delline();
  329.     }
  330.     row--;
  331.   }
  332.   
  333.   ScreenSetCursor(row, col);
  334.   txinfo.cury = row - txinfo.wintop + 2;
  335.   txinfo.curx = col - txinfo.winleft + 2;
  336.   return c;
  337. }
  338.  
  339. int getche(void)
  340. {
  341.   if (char_avail)
  342.     /*
  343.      * We don't know, wether the ungot char was already echoed
  344.      * we assume yes (for example in cscanf, probably the only
  345.      * place where ungetch is ever called.
  346.      * There is no way to check for this really, because
  347.      * ungetch could have been called with a character that
  348.      * hasn't been got by a conio function.
  349.      * We don't echo again.
  350.      */ 
  351.     return(getch());
  352.   return (putch(getch()));
  353. }
  354.  
  355. int getch(void)
  356. {
  357.     union REGS regs;
  358.     int c;
  359.     if (char_avail)
  360.     {
  361.         c = ungot_char;
  362.         char_avail = 0;
  363.     }
  364.     else
  365.     {
  366.         regs.x.ax = 0x0700;
  367.         int86(0x21, ®s, ®s);
  368.         c = regs.h.al;
  369.     }
  370.     return(c);
  371. }
  372.  
  373. int ungetch(int c)
  374. {
  375.     if (char_avail)
  376.         return(EOF);
  377.     ungot_char = c;
  378.     char_avail = 1;
  379.     return(c);
  380. }
  381.  
  382. /* 
  383.  * kbhit from libc in libsrc/c/dos/kbhit.s doesn't check
  384.  * for ungotten chars, so we have to provide a new one
  385.  * Don't call it kbhit, rather use a new name (_conio_kbhit)
  386.  * and do a #define kbhit _conio_kbhit in gppconio.h.
  387.  * The old kbhit still can be used if gppconio.h
  388.  * is not included of after #undef kbhit
  389.  * If you don't use ungetch (directly or indirectly by cscanf)
  390.  * both kbhit and _conio_kbhit are the same.
  391.  * So this shouldn't cause any trouble with previously written
  392.  * source, because ungetch wasn't available.
  393.  * The only problem might be, if anybody just included gppconio.h
  394.  * and has not linked with libpc, (I can't think of a good reason
  395.  * for this). This will result a link error (undefined symbol _conio_kbhit).
  396.  */
  397.  
  398. #undef kbhit  /* want to be able to call kbhit from libc */
  399.  
  400. int _conio_kbhit(void)
  401. {
  402.     if (char_avail)
  403.         return(1);
  404.     else
  405.         return(kbhit());
  406. }    
  407.  
  408. /*
  409.  * The next two functions are needed by cscanf
  410.  */
  411. static int _scan_getche(FILE *fp)
  412. {
  413.     return(getche());
  414. }
  415.  
  416. static int _scan_ungetch(int c, FILE *fp)
  417. {
  418.     return(ungetch(c));
  419. }
  420.  
  421.  
  422. void insline(void)
  423. {
  424.   int row, col, left, right, nbytes, bot, fill;
  425.   short line[txinfo.winright - txinfo.winleft + 1];
  426.   ScreenGetCursor(&row, &col);
  427.   left = txinfo.winleft - 1;
  428.   right = txinfo.winright - 1;
  429.   nbytes = (right-left+1)*2;
  430.   bot = txinfo.winbottom-1;
  431.   fill = ' ' | (ScreenAttrib << 8);
  432.   while(bot > row+1)
  433.     {
  434.       movedata(_go32_conventional_mem_selector(), VIDADDR(bot-1, left),
  435.                _go32_conventional_mem_selector(), VIDADDR(bot, left),
  436.                nbytes);
  437.       bot--;
  438.     }
  439.   if (row < txinfo.winbottom -1)
  440.     {
  441.       fillrow(row+1,left,right,fill);
  442.     }
  443. }
  444.  
  445.  
  446. void delline(void)
  447. {
  448.   int row, col, left, right, nbytes, bot, fill;
  449.   ScreenGetCursor(&row, &col);
  450.   left = txinfo.winleft - 1;
  451.   right = txinfo.winright - 1;
  452.   nbytes = (right-left+1)*2;
  453.   bot = txinfo.winbottom-1;
  454.   fill = ' ' | (ScreenAttrib << 8);
  455.   while(row < bot)
  456.     {
  457.       movedata(_go32_conventional_mem_selector(), VIDADDR(row+1, left),
  458.                _go32_conventional_mem_selector(), VIDADDR(row, left),
  459.                nbytes);
  460.       row++;
  461.     }
  462.   fillrow(bot,left,right,fill);
  463. }
  464.  
  465.  
  466. void window(int left, int top, int right, int bottom)
  467. {
  468.   if (top < 1 || left < 1 || right > txinfo.screenwidth ||
  469.       bottom > txinfo.screenheight)
  470.     return;
  471.   
  472.   txinfo.wintop = top;
  473.   txinfo.winleft = left;
  474.   txinfo.winright = right;
  475.   txinfo.winbottom = bottom;
  476.   gotoxy(1,1);
  477. }
  478.  
  479.  
  480. int cputs(const char *s)
  481. {
  482.   int     row, col,c;
  483.   const unsigned char *ss = (const unsigned char *)s;
  484.   short *viaddr;
  485.   short sa = ScreenAttrib << 8;
  486.   ScreenGetCursor(&row, &col);
  487.   viaddr = (short *)VIDADDR(row,col);
  488.   /* 
  489.    * Instead of just calling putch; we do everything by hand here,
  490.    * This is much faster. We don't move the cursor after each character,
  491.    * only after the whole string is written, because ScreenSetCursor
  492.    * needs to long because of switching to real mode needed with djgpp. 
  493.    * You won't recognize the difference.
  494.    */
  495.   while (c = *ss++)
  496.     {
  497.       /*  first, handle the character */
  498.       if (c == '\n')
  499.     {
  500.       row++;
  501.       viaddr += txinfo.screenwidth;
  502.     }
  503.       else if (c == '\r')
  504.     {
  505.       col = txinfo.winleft - 1;
  506.       viaddr = (short *)VIDADDR(row,col);
  507.     }
  508.       else if (c == '\b')
  509.         {
  510.           if (col > txinfo.winleft-1) 
  511.           {
  512.               col--;
  513.               viaddr--;
  514.           }
  515.           else if (row > txinfo.wintop -1)
  516.           {
  517.               /* 
  518.                * Turbo-C ignores this case. We want to be able to
  519.                * edit strings with backspace in gets after
  520.                * a linefeed, so we are smarter
  521.                */
  522.               row--;
  523.               col = txinfo.winright-1;
  524.               viaddr = (short *)VIDADDR(row,col);
  525.           }
  526.         }
  527.       else if (c == 0x07)
  528.           bell();
  529.       else {
  530.         short q = c | sa;
  531.         dosmemput(&q, 2, (int)viaddr);
  532.     viaddr++;
  533.     col++;
  534.       }
  535.       
  536.       /* now, readjust the window     */
  537.       
  538.       if (col >= txinfo.winright) {
  539.     col = txinfo.winleft - 1;
  540.     row++;
  541.     viaddr = (short *)VIDADDR(row,col);
  542.       }
  543.       
  544.       if (row >= txinfo.winbottom) {
  545.     ScreenSetCursor(txinfo.wintop-1,0); /* goto first line in window */
  546.     delline();                          /* and delete it */
  547.     row--;
  548.     viaddr -= txinfo.screenwidth;
  549.       }
  550.     }
  551.   
  552.   ScreenSetCursor(row, col);
  553.   txinfo.cury = row - txinfo.wintop + 2;
  554.   txinfo.curx = col - txinfo.winleft + 2;
  555.   return(*(--ss));
  556. }
  557.  
  558.  
  559. int cprintf(const char *fmt, ...)
  560. {
  561.   int     cnt;
  562.   char    buf[ 2048 ]; /* this is buggy, because buffer might be too small. */
  563.   va_list ap;
  564.   
  565.   va_start(ap, fmt);
  566.   cnt = vsprintf(buf, fmt, ap);
  567.   va_end(ap);
  568.   
  569.   cputs(buf);
  570.   return cnt;
  571. }
  572.  
  573. char *cgets(char *string)
  574. {
  575.     unsigned len = 0;
  576.     unsigned int maxlen_wanted;
  577.     char *sp;
  578.     int c;
  579.     /*
  580.      * Be smart and check for NULL pointer.
  581.      * Don't know wether TURBOC does this.
  582.      */
  583.     if (!string)
  584.         return(NULL);
  585.     maxlen_wanted = (unsigned int)((unsigned char)string[0]);
  586.     sp = &(string[2]);
  587.     /* 
  588.      * Should the string be shorter maxlen_wanted including or excluding
  589.      * the trailing '\0' ? We don't take any risk.
  590.      */
  591.     while(len < maxlen_wanted-1)
  592.     {
  593.         c=getch();
  594.         /*
  595.          * shold we check for backspace here?
  596.          * TURBOC does (just checked) but doesn't in cscanf (thats harder
  597.          * or even impossible). We do the same.
  598.          */
  599.         if (c == '\b')
  600.         {
  601.             if (len > 0)
  602.             {
  603.                cputs("\b \b"); /* go back, clear char on screen with space
  604.                                   and go back again */
  605.                len--;
  606.                sp[len] = '\0'; /* clear the character in the string */
  607.             }
  608.         }
  609.         else if (c == '\r')
  610.         {
  611.             sp[len] = '\0';
  612.             break;
  613.         }
  614.         else if (c == 0)
  615.         {
  616.             /* special character ends input */
  617.             sp[len] = '\0';
  618.             ungetch(c); /* keep the char for later processing */
  619.             break;
  620.         }
  621.         else
  622.         {
  623.            sp[len] = putch(c);
  624.            len++;
  625.         }
  626.      }
  627.      sp[maxlen_wanted-1] = '\0';
  628.      string[1] = (char)((unsigned char)len);
  629.      return(sp);   
  630. }    
  631.  
  632. int cscanf(const char *fmt, ...)
  633. {
  634.     return(_doscan_low(NULL, _scan_getche, _scan_ungetch, 
  635.                        fmt, (void **)((&fmt)+1)));
  636. }
  637.  
  638. int movetext(int left, int top, int right, int bottom, int dleft, int dtop)
  639. {
  640.   char    *buf = malloc((right - left + 1) * (bottom - top + 1) * 2);
  641.   
  642.   if (!buf)
  643.     return 0;
  644.   
  645.   gettext(left, top, right, bottom, buf);
  646.   puttext(dleft, dtop, dleft + right - left, dtop + bottom - top, buf);
  647.   free(buf);
  648.   return 1;
  649. }
  650.  
  651. static void _gettextinfo(struct text_info *t)
  652. {
  653.   int row, col;
  654.   
  655.   t->winleft = t->wintop = 1;
  656.   t->winright = t->screenwidth = ScreenCols();
  657.   t->winbottom = t->screenheight = ScreenRows();
  658.   ScreenAttrib = t->attribute = t->normattr = get_screenattrib();
  659.   t->currmode = getvideomode();
  660.   ScreenGetCursor(&row, &col);
  661.   t->curx = col+1;
  662.   t->cury = row+1;
  663. #if DBGGTINFO
  664.   printf("left=%2d,right=%2d,top=%2d,bottom=%2d\n",t->winleft,
  665.      t->winright,t->wintop,t->winbottom);
  666.   printf("scrht=%2d,scrwid=%2d,norm=%2x,mode=%2d,x=%2d,y=%2d\n",
  667.      t->screenheight, t->screenwidth, t->normattr, t->currmode,
  668.      t->curx, t->cury);
  669. #endif
  670. }
  671.  
  672. void gettextinfo(struct text_info *t)
  673. {
  674.   *t = txinfo; 
  675. #if DBGGTINFO
  676.   printf("left=%2d,right=%2d,top=%2d,bottom=%2d\n",t->winleft,
  677.      t->winright,t->wintop,t->winbottom);
  678.   printf("scrht=%2d,scrwid=%2d,norm=%2x,mode=%2d,x=%2d,y=%2d\n",
  679.      t->screenheight, t->screenwidth, t->normattr, t->currmode,
  680.      t->curx, t->cury);
  681. #endif
  682. }
  683.  
  684. static int
  685. getvideomode(void)
  686. {
  687.     int mode = ScreenMode();
  688.     /* 
  689.      * in mode C80 we might have loaded a different font
  690.      */
  691.     if (mode == C80)
  692.         if (ScreenRows() > 25)
  693.            mode = C4350;
  694.     return(mode);
  695. }
  696.     
  697.  
  698. static void bell(void)
  699. {
  700.     union REGS regs;
  701.     regs.h.ah = 0x0e; /* write */
  702.     regs.h.al = 0x07; /* bell */
  703.     int86(0x10, ®s, ®s);
  704. }
  705.  
  706. static int 
  707. get_screenattrib(void)
  708. {
  709.     union REGS regs;
  710.     regs.h.ah = 0x08; /* read character and attribute */
  711.     regs.h.bh = 0;    /* video page 0 */
  712.     int86(0x10, ®s, ®s);
  713.     return(regs.h.ah & 0x7f); /* strip highest (BLINK) bit */
  714. }
  715.  
  716. /* check if we have at least EGA (idea form Ralf Browns interrupt list) */
  717. static int
  718. isEGA(void)
  719. {
  720.     union REGS regs;
  721.     regs.h.ah = 0x12;
  722.     regs.h.bl = 0x10;
  723.     regs.h.bh = 0xff;
  724.     int86(0x10, ®s, ®s);
  725.     return(regs.h.bh != 0xff);
  726. }
  727.  
  728.  
  729. extern int _gppconio_init;
  730.  
  731. void gppconio_init(void)
  732. {
  733.     static int oldattrib =  -1;
  734.     if (oldattrib == -1)
  735.         oldattrib = get_screenattrib();   
  736.     _gettextinfo(&txinfo);
  737.     if (txinfo.currmode == 7)    /* MONO */
  738.         ScreenAddress = 0xb0000UL;
  739.     else
  740.     ScreenAddress = 0xb8000UL;
  741.     ScreenAttrib = txinfo.normattr = txinfo.attribute = oldattrib;
  742.     _gppconio_init = 1;
  743. }
  744.  
  745.